package com.katesoft.scale4j.persistent.client;

import java.util.List;

import net.jcip.annotations.ThreadSafe;

import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateOperations;
import org.springframework.orm.jpa.JpaOperations;

import com.katesoft.scale4j.persistent.model.unified.AbstractPersistentEntity;

/**
 * This is extended(local) interface for well-known {@link HibernateOperations} interface.
 * <p/>
 * Few specific methods defined on top of IBO domain class, also some useful methods, that are not
 * present in standard HibernateOperations interface added.
 * 
 * @author kate2007
 * @see LocalHibernateTemplate
 * @see IHibernateOperations
 */
@ThreadSafe
public interface IHibernateOperations extends HibernateOperations, JpaOperations {
   /**
    * looking for entity for update by unique identifier and comparing with expectedVersion - if
    * actual version matches with expected, then return entity.
    * 
    * @param entityClass
    *           persistent class
    * @param uniqueIdentifier
    *           primary key
    * @param expectedVersion
    *           version that client is working with
    * @param <T>
    *           domain entity type
    * @return domain entity, never return <code>null</code>.
    * @throws org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException
    *            if actual version does not match with expectedVersion.
    * @throws org.springframework.dao.EmptyResultDataAccessException
    *            if domain entity with given identifier does not exists.
    * @throws DataAccessException
    *            in case of SQL exception
    */
   <T extends AbstractPersistentEntity> T findEntityForUpdate(Class<T> entityClass,
            long uniqueIdentifier, long expectedVersion) throws DataAccessException;

   /**
    * Return all persistent instances of the given entity class calling
    * AbstractPersistentEntity.forceAttributesLoad method if necessary.
    * <p/>
    * Note: Use queries or criteria for retrieving a specific subset.
    * 
    * @param entityClass
    *           a persistent class
    * @param forceDirtyLoad
    *           to force load? this means that forceAttributesLoad method will be invoked if
    *           necessary.
    * @return a {@link List} containing 0 or more persistent instances
    * @throws org.springframework.dao.DataAccessException
    *            if hibernate error or SQL exception occurs.
    * @see com.katesoft.scale4j.persistent.model.base.IDirtyLoadableEntity#forceAttributesLoad()
    */
   <T extends AbstractPersistentEntity> List<T> loadAll(Class<T> entityClass, boolean forceDirtyLoad)
            throws DataAccessException;

   /**
    * delete all entities of the specific class.
    * 
    * @param clazz
    *           entity to delete.
    * @throws org.springframework.dao.DataAccessException
    *            if hibernate error or SQL exception occurs.
    */
   void deleteAll(final Class<?> clazz) throws DataAccessException;

   /**
    * perform entity load by provided global unique identifier.
    * 
    * @param persistentClazz
    *           domain class.
    * @param guid
    *           global unique identifier of entity.
    * @param forceDirtyLoad
    *           to force load? this means that forceAttributesLoad method will be invoked if
    *           necessary.
    * @param <T>
    *           type of entity.
    * @return loaded entity or <code>null</code>.
    * @throws org.springframework.dao.DataAccessException
    *            if hibernate error or SQL exception occurs.
    * @see com.katesoft.scale4j.persistent.model.unified.IBO#getGlobalUniqueIdentifier()
    */
   <T extends AbstractPersistentEntity> T loadByGlobalUniqueIdentifier(Class<T> persistentClazz,
            String guid, boolean forceDirtyLoad) throws DataAccessException;

   /**
    * perform entity load by provided global unique identifier across all tables.
    * <p/>
    * ideally query should not cause performance issue as global unique columns indexed.
    * <p/>
    * should be used for testing purpose in most cases.
    * 
    * @param guid
    *           global unique identifier of entity.
    * @param forceDirtyLoad
    *           to force load? this means that forceAttributesLoad method will be invoked if
    *           necessary.
    * @param <T>
    *           type of entity.
    * @return loaded entity or <code>null</code>.
    * @throws org.springframework.dao.DataAccessException
    *            if hibernate error or SQL exception occurs.
    * @see com.katesoft.scale4j.persistent.model.unified.IBO#getUniqueIdentifier()
    */
   <T extends AbstractPersistentEntity> T loadByGlobalUniqueIdentifier(String guid,
            boolean forceDirtyLoad) throws DataAccessException;
}
